﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Brio.Framework;

namespace Brio
{
    public class MotifStatistics
    {
        public MotifStatistics()
        {
            statsGensMatrix = new List<List<Tuple<double, double>>>();
            statsGenMatrix = new List<Tuple<double, double>>();

            statsRunMatrix = new List<Tuple<double, double>>();

            // Initialize Run Matrix
            for (int R = 0; R < Settings.Generations; R++)
            {
                statsRunMatrix.Add(new Tuple<double, double>(0.0, 0.0));
            }

        }

        private List<List<Tuple<double, double>>> statsGensMatrix;
        private List<Tuple<double, double>> statsGenMatrix;

        private List<Tuple<double, double>> statsRunMatrix;



        private double statsRunSTD;

        public void AddGeneration(double averageFitness, double averageFitnessSTD)
        {
            statsGenMatrix.Add(new Tuple<double, double>(averageFitness, averageFitnessSTD));

            int index = statsGenMatrix.Count - 1;

            // TODO: this seems like it would be slow.
            statsRunMatrix[index] = new Tuple<double, double>(statsRunMatrix[index].Item1 + averageFitness, statsRunMatrix[index].Item2);
        }

        public void EndRun()
        {
            List<Tuple<double, double>> clonedGenMatrix = statsGenMatrix.GetRange(0, statsGenMatrix.Count);


            // EDIT: WRONG STATS APPROACH
            /*
            double sumFitness = clonedGenMatrix.Sum(series => series.Item1);
            // Sum all of the chromosome's fitnesses squared.
            double sumFitnessSquared = clonedGenMatrix.Sum(series => Math.Pow(series.Item1, 2.0));


            // Average Fitness of the generation
            double avgRunFitness = sumFitness / clonedGenMatrix.Count;

            double avgRunFitnessSquared = Math.Pow(avgRunFitness, 2.0);
            */

            // Add a whole runs worth of data to the run matrix. A run contains the avg run fitness, the avg run fitness^2 as well as 
            // each generations stats
            statsGensMatrix.Add(new List<Tuple<double, double>>(clonedGenMatrix));


            // Get ready for next runs generations
            statsGenMatrix.Clear();
        }

        public void EndRuns()
        {
            //TODO: Move math to MotifStatistics

            for (int G = 0; G < Settings.Generations; G++)
            {
                // Set Fitness Squared
                statsRunMatrix[G] = new Tuple<double, double>(statsRunMatrix[G].Item1, Math.Pow(statsRunMatrix[G].Item1, 2.0));

                // IMPORTANT NOTE:
                // Okay, this is not the best practice but
                // Originally Tuple<double,double> stored sumFitness, sumFitnessSquared
                // it will now store Tuple<double,double> = avgFitness stdavgFitness
                // TODO: Implement this in a non confusing manner.

                // Average Fitness of the generation
                double avgGenFitness = statsRunMatrix[G].Item1 / Settings.PopulationSize;

                // STD of average fitness of the generation
                double avgStdGenFitness = Math.Sqrt(
                                             Math.Abs(statsRunMatrix[G].Item2 -
                                                      statsRunMatrix[G].Item1 * statsRunMatrix[G].Item1 / Settings.PopulationSize)
                                                      /
                                                      (Settings.PopulationSize - 1));


                // Change tuple to store avgFitness stdAvgFitness
                statsRunMatrix[G] = new Tuple<double, double>(avgGenFitness, avgStdGenFitness);
            }


        }

    }

}